﻿
using System;
using System.IO;
using System.Collections;

namespace CCompiler {
    public class Token {
        public TokenCode code;
        public int value;
        public string lexeme;

        public Token(TokenCode code, string lexeme) {
            this.code = code;
            this.lexeme = lexeme;
        }

        public Token(TokenCode code, string lexeme, int value)
            : this(code, lexeme) {
            this.value = value;
        }

        public override string ToString() {
            return lexeme;
        }
    }

    /* basic data types */
    public enum Type {
        Char, Integer, Void
    }

    public enum VariableKind {
        Local, Argument
    }

    public class Symbol {
        public string lexeme;
        public TokenCode code;


        public Symbol(string lexeme, TokenCode code) {
            this.lexeme = lexeme;
            this.code = code;
        }
    }

    public class VariableSymbol : Symbol {
        public int offset;
        public int elemSize;
        public int size;
        public bool isArray;
        //public bool isTemp;
        public Type type;
        public VariableKind kind;

        public VariableSymbol(string id)
            : base(id, TokenCode.Id) {
        }
    }

    public class Parameter {
        public Type type;
        public string id;
        public bool isArray;

        public Parameter(Type type, string id, bool isArray) {
            this.type = type;
            this.id = id;
            this.isArray = isArray;
        }
    }

    public class FunctionSymbol : Symbol {
        public Type returnType;
        public ArrayList parameters;

        public FunctionSymbol(string id)
            : base(id, TokenCode.Id) {
            parameters = new ArrayList();
        }
    }

    public class SymbolTable {
        public Hashtable table;
        public SymbolTable prev;
        public ArrayList childScopes;

        public SymbolTable(SymbolTable prev) {
            table = new Hashtable();
            this.prev = prev;
            childScopes = new ArrayList();
        }

        public Symbol Lookup(string lexeme) {
            SymbolTable curTable = this;
            do {
                Symbol sym = (Symbol)curTable.table[lexeme];
                if (sym != null)
                    return sym;

                curTable = curTable.prev;

            } while (curTable != null);

            return null;
        }

        public bool LookupInCurScope(string lexeme) {
            return table[lexeme] != null;
        }

        public void Insert(Symbol symbol) {
            table.Add(symbol.lexeme, symbol);
        }

        public void Insert(string lexeme, TokenCode code) {
            Insert(new Symbol(lexeme, code));
        }
    }
}